﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using AlgorithmResult;
using System.Windows.Forms.DataVisualization.Charting;
using PermutationCl;
using System.Globalization;

using Microsoft.Office.Interop.Excel;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using System.Threading;


namespace TripletSegmentationGUI
{

    public partial class AlgorithmResultView : UserControl
    {
        private static bool isTitlePrinted = false;
        BoundaryPositionTabletable statisticalView = null;
       public IParameters Params {get;set;}
        protected Result algresult = null;
        protected String Text = String.Empty;
        protected System.Data.DataTable table = null;

        //List to hold list view Item Cache.
        List<ListViewItem> m_ListItemCache = new List<ListViewItem>();

        // ListViewItem, IComparer<ListViewItem> class to sort list view item
        ListViewColumnSorter m_lvwColumnSorter = new ListViewColumnSorter();

        float similarityRate = 0;

        public AlgorithmResultView(Result algresult,IParameters param)
        {
            InitializeComponent();
            if (algresult != null)
            {

                this.algresult = algresult;
                this.Text = algresult.Text;
                Params = param;
                similarityRate = (float)(algresult.TotalIndividualSimilarity * 100);
                //  statisticalView = new BoundaryPositionTabletable(algresult, _codonSize);
                DataTableResult tableManager = new DataTableResult();
                table = tableManager.CreateDataTable(algresult, algresult.CodonSize);
                statisticalView = new BoundaryPositionTabletable(table);
               
                StatisticalViewPAge.Controls.Add(statisticalView);
                statisticalView.Dock = DockStyle.Fill;
                //     InitChart(statisticalView.GetDataGridViewTable());

                GraphParamscomboBox.Items.Add(DataTableResult.STR_NumberOfFragments);
                GraphParamscomboBox.Items.Add(DataTableResult.STR_SumOfTripletsExpansion);
                GraphParamscomboBox.Items.Add(DataTableResult.STR_AverageFragmentLength);
                GraphParamscomboBox.Items.Add(DataTableResult.STR_AverageFragmentSimilarity);
                GraphParamscomboBox.Items.Add(DataTableResult.STR_AverageContributionLength);
                GraphParamscomboBox.Items.Add(DataTableResult.STR_AverageSimilarityStrengthRate);
                GraphParamscomboBox.Items.Add(DataTableResult.STR_AverageLengthStrengthRate);


                GraphParamscomboBox.SelectedIndex = 0;

                //            InitChart(table, DataTableResult.STR_NumberOfFragments);
               
                if (algresult.CodonSize < 8)
                {
                    PrintText(algresult);
                    InitChart();
                    comboBox1.Items.AddRange(Enum.GetNames(typeof(SeriesChartType)));
                    comboBox1.SelectedIndex = 10;
                    InitGraphicView(algresult, tableManager);
                }

                CalculateTotalResults(tableManager);
            }



        }
        void writeResultsToFile(StringBuilder stream)
        {
            using (StreamWriter w = File.AppendText("C:\\myFile.txt"))
            {
                w.WriteLine(stream);
                w.Flush();
                w.Close();
            }


        }
        private void CalculateTotalResults(DataTableResult tableManager)
        {
          //  totalListView
                 ListViewItem item = new ListViewItem("Total similarity rate(%)");
                item.UseItemStyleForSubItems = false;
                item.SubItems.Add((algresult.TotalIndividualSimilarity *100).ToString());
                totalListView.Items.Add(item);
            
               item = new ListViewItem("Total Strength similarity");
                item.UseItemStyleForSubItems = false;
                float strengh_sim=0;
                float strngth_len = 0;
                for (int i = 0; i < tableManager.Table.Rows.Count; ++i)
                {
                    strengh_sim += (float)tableManager.Table.Rows[i][DataTableResult.STR_AverageSimilarityStrengthRate];
                    strngth_len += (float)tableManager.Table.Rows[i][DataTableResult.STR_AverageLengthStrengthRate];
                }
                item.SubItems.Add(strengh_sim.ToString());
                totalListView.Items.Add(item);
                item = new ListViewItem("Total Strength length");
                item.SubItems.Add(strngth_len.ToString());
                totalListView.Items.Add(item);

                item = new ListViewItem("Standart deviation length");
                StandartDeviation dev = new StandartDeviationLength(tableManager.Table, algresult, tableManager.CodonMap);
                double  deviation =dev.CalculateStandardDeviation();
                item.SubItems.Add(deviation.ToString());
                totalListView.Items.Add(item);

                item = new ListViewItem("Standart deviation similarity");
                dev = new StandartDeviationRate(tableManager.Table, algresult, tableManager.CodonMap);
                deviation = dev.CalculateStandardDeviation();
                item.SubItems.Add(deviation.ToString());
                totalListView.Items.Add(item);
                totalListView.ContextMenuStrip = contextMenuStrip1;

                StringBuilder buffer = null;
                if (isTitlePrinted == false)
                {
                     buffer = Params.GetParamsNames();
                    buffer.Append(GetTotalListNames(totalListView));
                    //  buffer = Params.ToString();
                    //  buffer.Append(CopyListViewToClipboard(totalListView).ToString());
                    //  buffer.Append("************************************************");
                    buffer.Append("\r\n");
                    writeResultsToFile(buffer);
                    isTitlePrinted = true; 
                }
                buffer = Params.GetParamsValue();
                buffer.Append(GetTotalListValues(totalListView));
          //      buffer.Append("\n");
                writeResultsToFile(buffer);
             
               
        }
        private StringBuilder GetTotalListNames(ListView lv)
        {
            StringBuilder buffer = new StringBuilder();
            for (int i = 0; i < lv.Items.Count; i++)
            {
                
                    buffer.Append(lv.Items[i].Text);
                    buffer.Append("\t");
            }
            return buffer;
        }
        private StringBuilder GetTotalListValues(ListView lv)
        {
            StringBuilder buffer = new StringBuilder();
            for (int i = 0; i < lv.Items.Count; i++)
            {

                buffer.Append(lv.Items[i].SubItems[1].Text);
                if (i < lv.Items.Count-1)
                  buffer.Append("\t");
            }
            return buffer;
        }
        public StringBuilder CopyListViewToClipboard(ListView lv)
        {
            StringBuilder buffer = new StringBuilder();

            for (int i = 0; i < lv.Columns.Count; i++)
            {
                buffer.Append(lv.Columns[i].Text);
                buffer.Append("\t");
            }

            buffer.Append("\r\n");

            for (int i = 0; i < lv.Items.Count; i++)
            {
                for (int j = 0; j < lv.Columns.Count; j++)
                {
                    buffer.Append(lv.Items[i].SubItems[j].Text);
                    buffer.Append("\t");
                }

                buffer.Append("\r\n");
            }

            Clipboard.SetText(buffer.ToString());
            return buffer;
        }  

        private void PrintText(Result algresult)
        {
            TextualViewtextBox.Text = String.Join(" ", algresult.ArchreTriplets);
        }

        int deltaScrollTotal;
        private void chart_MouseWheel(object sender, MouseEventArgs e)
        {
            try
            {
                if (tabControl1.SelectedTab == HistogramViewPage)
                {
                    int maxChangeRange = 100;
                    int minChangeRange = -100;
                    if (e.Delta != 0)
                    {
                        int deltaScroll = e.Delta / (Math.Abs(e.Delta));
                        deltaScrollTotal += deltaScrollTotal + deltaScroll > minChangeRange
                                         && deltaScrollTotal + deltaScroll < maxChangeRange
                                          ? deltaScroll : 0;
                        // Additional calculation in order to obtain pseudo
                        // "positional zoom" feature
                        double minXScale = (double)e.X / (double)CodonGraph.Width;
                        double maxXScale = 1 - minXScale;
                        double minYScale = (double)e.Y / (double)CodonGraph.Height;
                        double maxYScale = 1 - minYScale;

                        // Max and min values into which axis need to be scaled/zoomed
                        double maxX = CodonGraph.ChartAreas[0].AxisX.Maximum
                                    - deltaScrollTotal * maxXScale;
                        double minX = CodonGraph.ChartAreas[0].AxisX.Minimum
                                    + deltaScrollTotal * minXScale;
                        double maxY = CodonGraph.ChartAreas[0].AxisY.Maximum
                                    - deltaScrollTotal * minYScale;
                        double minY = CodonGraph.ChartAreas[0].AxisY.Minimum
                                    + deltaScrollTotal * maxYScale;

                        CodonGraph.ChartAreas[0].AxisX.ScaleView.Zoom(minX, maxX);
                        CodonGraph.ChartAreas[0].AxisY.ScaleView.Zoom(minY, maxY);
                    }
                }
            }
            catch (Exception ex) { MessageBox.Show(ex.Message); }
        }
        private void InitChart()
        {
            this.MouseWheel += chart_MouseWheel;


            this.CodonGraph.Titles.Add(String.Format("Ancient Triplet Segmentation Distribution ,similarity rate {0} %", similarityRate));
        }

        private void DrawChart(System.Data.DataTable table, String ParamName)
        {
            //    try
            {
                int j = 0;
                this.CodonGraph.ChartAreas.Clear();
                this.CodonGraph.Series.Clear();

                this.CodonGraph.ChartAreas.Add(ParamName);
                System.Windows.Forms.DataVisualization.Charting.Series NumOfTripletSeries = this.CodonGraph.Series.Add(ParamName);

                //     Series LengthSeries = this.CodonGraph.Series.Add("Cumulative length");
                // LengthSeries.ChartType = SeriesChartType.FastLine;
                NumOfTripletSeries.Palette = ChartColorPalette.Bright;
                CodonGraph.ChartAreas.ElementAt(0).AxisX.Title = "Codons";
                CodonGraph.ChartAreas.ElementAt(0).AxisY.Title = ParamName;
                /*
                 CodonGraph.DataSource=table;
                 NumOfTripletSeries.XValueMember=DataTableResult.STR_Codon;
                 NumOfTripletSeries.XAxisType = AxisType.Primary;
                 NumOfTripletSeries.XValueType = ChartValueType.Auto;
                 NumOfTripletSeries.IsXValueIndexed = true;

                 NumOfTripletSeries.IsVisibleInLegend = true;
                 NumOfTripletSeries.YValuesPerPoint = 10000;
              
                 NumOfTripletSeries.YValueMembers=ParamName;
                 NumOfTripletSeries.IsValueShownAsLabel = true;
                  * */
                for (int i = 0; i < table.Rows.Count; i++)
                {

                    using (DataPoint point = new DataPoint() { Label = (String)table.Rows[i][DataTableResult.STR_Codon] })
                    {
                        double[] yValues = new double[1];
                        Type type = table.Rows[i][ParamName].GetType();
                        switch (type.Name)
                        {
                            case "Int32":
                                yValues[0] = (int)table.Rows[i][ParamName];
                                break;
                            case "Double":
                                yValues[0] = (double)table.Rows[i][ParamName];
                                break;
                            case "Int64":
                                yValues[0] = (int)((long)table.Rows[i][ParamName]);
                                break;
                            case "Single":
                                yValues[0] = (float)table.Rows[i][ParamName];
                                break;
                        }
                        //yValues[0] = (int)table.Rows[i][ParamName];
                        point.YValues = yValues;
                        point.ToolTip = String.Format("{0} {1}", point.Label, table.Rows[i][ParamName]);
                        point.YValues = yValues;
                        NumOfTripletSeries.Points.Add(point);
                    }




                }



            }
            //   catch (Exception ex) { MessageBox.Show(ex.Message); }

        }

        private void SaveGraph()
        {


        }
        private void InitChart(DataGridView dataGridView)
        {
            try
            {
                int j = 0;
                this.MouseWheel += new MouseEventHandler(chart_MouseWheel);

                this.CodonGraph.Titles.Add("Ancient Triplet Segmentation Distribution");
                System.Windows.Forms.DataVisualization.Charting.Series NumOfTripletSeries = this.CodonGraph.Series.Add("Number of Triplets");

                //     Series LengthSeries = this.CodonGraph.Series.Add("Cumulative length");
                // LengthSeries.ChartType = SeriesChartType.FastLine;
                NumOfTripletSeries.Palette = ChartColorPalette.Bright;
                for (int i = 0; i < dataGridView.RowCount; i++)
                {

                    DataPoint point = new DataPoint();
                    if (dataGridView[1, i].Value != null)
                    {

                        point.Label = (String)(dataGridView[1, i].Value);
                        //      Series NumOfTripletSeries = this.CodonGraph.Series.Add(point.Label);
                        double[] yValues = new double[1];
                        if (dataGridView[3, i].Value == null)
                        {
                            yValues[0] = 0;
                            point.YValues = yValues;

                            NumOfTripletSeries.Points.Add(point);

                            //       LengthSeries.Points.Add(point);
                        }
                        else
                        {
                            yValues[0] = (int)(dataGridView[3, i].Value);
                            //    NumOfTripletSeries.Legend.Insert(i, point.Label);
                            point.ToolTip = String.Format("{0} {1}", point.Label, (int)(dataGridView[3, i].Value));
                            point.YValues = yValues;
                            NumOfTripletSeries.Points.Add(point);


                        }



                    }

                }
            }
            catch (Exception ex) { MessageBox.Show(ex.Message); }
        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                if (CodonGraph != null && CodonGraph.Series.Count != 0)
                    CodonGraph.Series[0].ChartType = (SeriesChartType)Enum.Parse(typeof(SeriesChartType), (String)comboBox1.SelectedItem);

            }
            catch (Exception ex) { MessageBox.Show(ex.Message); }
        }


        private List<ListViewItem> CreateTestDataList(int count, DataTableResult tableResult)
        {

            List<ListViewItem> list = new List<ListViewItem>();



            for (int i = 0; i < count; i++)
            {


                String boundary = (i == 0 ? "0-" + (algresult.BoundariesSet[i]-1) : (algresult.BoundariesSet[i - 1] + "-" + (algresult.BoundariesSet[i]-1)));
                ListViewItem item = new ListViewItem(boundary);
                item.UseItemStyleForSubItems = false;
                item.SubItems.Add(algresult.ArchreTriplets[i]);


                //      item.Group=GraphclistView.Groups[algresult.ArchreTriplets[i]];
                if (i == 0)
                {
                    long length=algresult.BoundariesSet[i];
                    float lengthContribution=((float)((double)length / (double)Text.Length) * 100);
                    float similarityRate=(algresult.SimilarityToAncientCodon[i] * 100);
                    float segmentStrength=(float)((similarityRate * lengthContribution)/100);
                    item.SubItems.Add(similarityRate.ToString());
                    item.SubItems.Add(lengthContribution.ToString());
                    item.SubItems.Add(segmentStrength.ToString());

                    item.SubItems.Add(length.ToString());
                    item.SubItems.Add(Text.Substring(0, (int)algresult.BoundariesSet[i]));
                }
                else
                {
                    long length = (int)algresult.BoundariesSet[i] - (int)algresult.BoundariesSet[i - 1];
                    float lengthContribution = ((float)((double)length / (double)Text.Length) * 100);
                    float similarityRate = (algresult.SimilarityToAncientCodon[i] * 100);
                    float segmentStrength = (float)((similarityRate * lengthContribution) / 100);
                    item.SubItems.Add(similarityRate.ToString());
                    item.SubItems.Add(lengthContribution.ToString());
                    item.SubItems.Add(segmentStrength.ToString());

                    item.SubItems.Add(length.ToString());
                    item.SubItems.Add(Text.Substring((int)algresult.BoundariesSet[i - 1],
                    (int)algresult.BoundariesSet[i] - (int)algresult.BoundariesSet[i - 1]));
                }
                list.Add(item);

            }

            return list;

        }
        void InitGraphicView(Result algresult,DataTableResult tableResult)
        {
            InitGropus(algresult.CodonSize);
            GraphclistView.VirtualListSize = algresult.NumOfBoundaries;
            m_ListItemCache = CreateTestDataList(algresult.NumOfBoundaries, tableResult);


        }

        private void InitGropus(int _codonSize)
        {


            string[] nucls = Enum.GetNames(typeof(CodonSegDP.NUCLEOTID));
            Variations<string> variations = new Variations<string>(nucls, _codonSize, GenerateOption.WithRepetition);
            String codonName = String.Empty;
            foreach (IList<string> v in variations)
            {
                codonName = String.Empty;
                //   dataGridViewTable[0, index].Value = index;
                for (int j = 0; j < _codonSize; ++j)
                {
                    codonName += (String)(v[j]);


                }
                GraphclistView.Groups.Add(codonName, codonName);
            }

        }

        private void GraphclistView_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            // Determine if clicked column is already the column that is being sorted.

            if (e.Column == m_lvwColumnSorter.SortColumn)
            {
                // Reverse the current sort direction for this column.
                if (m_lvwColumnSorter.Order == SortOrder.Ascending)
                {
                    m_lvwColumnSorter.Order = SortOrder.Descending;
                }
                else
                {
                    m_lvwColumnSorter.Order = SortOrder.Ascending;
                }
            }
            else
            {
                // Set the column number that is to be sorted; default to ascending.
                m_lvwColumnSorter.SortColumn = e.Column;
                m_lvwColumnSorter.Order = SortOrder.Ascending;
            }

            //Sort LitViewItem list depend upon column

            this.m_ListItemCache.Sort(m_lvwColumnSorter);

            this.GraphclistView.VirtualListSize = 0;

            this.GraphclistView.Update();

            this.GraphclistView.VirtualListSize = this.m_ListItemCache.Count;

            this.GraphclistView.Update();



        }

        private void GraphclistView_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
        {
            if (e.ItemIndex >= this.m_ListItemCache.Count)
            {

                //If Item index is out of range then create item with empty records

                e.Item = new ListViewItem("");

                e.Item.SubItems.Add("");

                e.Item.SubItems.Add("");

            }

            else
            {

                e.Item = m_ListItemCache[e.ItemIndex];//Show item

            }

        }

        private void GraphclistView_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
        {
            if (e.IsSelected)
            {

                ListViewItem selitem = e.Item;

            }
        }

        private void ShowWhiteSpaceCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (ShowWhiteSpaceCheckBox.CheckState == CheckState.Checked)
            {
                TextualViewtextBox.Text = String.Join(" ", algresult.ArchreTriplets);
            }
            else
            {
                TextualViewtextBox.Text = String.Join("", algresult.ArchreTriplets);
            }
        }

        private void GraphParamscomboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            DrawChart(table, GraphParamscomboBox.SelectedItem.ToString());
        }



        private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // SaveFileDialog saveFileDialog1 = new SaveFileDialog(); 
            saveFileDialogAlgorithmResult.InitialDirectory = Convert.ToString(Environment.SpecialFolder.MyDocuments);
            saveFileDialogAlgorithmResult.Filter = "Algorithm results (*.Res)|*.res";
            saveFileDialogAlgorithmResult.FilterIndex = 1;

            if (saveFileDialogAlgorithmResult.ShowDialog() == DialogResult.OK)
            {
                Save(algresult, saveFileDialogAlgorithmResult.FileName);

                // Console.WriteLine(saveFileDialogAlgorithmResult.FileName);//Do what you want here
            }
        }

        static void Save(Result result, string fileName)
        {
            Stream stream = null;
            try
            {
                IFormatter formatter = new BinaryFormatter();
                stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None);
                //formatter.Serialize(stream, VERSION);
                formatter.Serialize(stream, result);
            }
            catch
            {
                // do nothing, just ignore any possible errors
            }
            finally
            {
                if (null != stream)
                    stream.Close();
            }

        }

        static Result Load(string fileName)
        {
            Stream stream = null;
            Result result = null;
            try
            {
                IFormatter formatter = new BinaryFormatter();
                stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.None);
                // int version = (int)formatter.Deserialize(stream);
                // Debug.Assert(version == VERSION);
                result = (Result)formatter.Deserialize(stream);
            }
            catch
            {
                // do nothing, just ignore any possible errors
            }
            finally
            {
                if (null != stream)
                    stream.Close();
            }
            return result;
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Result result = null;
            // Show the dialog and get result.
            DialogResult dialogResult = openFileDialogAlgorithmResult.ShowDialog();
            
            if (dialogResult == DialogResult.OK) // Test result.
            {
                result = Load(openFileDialogAlgorithmResult.FileName);
                algresult = result;
            }
            Console.WriteLine(result); // <-- For debugging use only.
        }

        private void copyToolStripMenuItem_Click(object sender, EventArgs e)
        {
            CopyListViewToClipboard(totalListView);
        }
    }

}
